package com.langerra.client.channel;

import com.google.gwt.user.client.Timer;
import com.google.gwt.user.client.rpc.AsyncCallback;

/**
 * This class makes sure that a the server has a long poll on a resource. also
 * limits the total number of polling requests it sends to the server
 * 
 * example: {@code final String sessionId = ?; final ApiGeneric api = ?;
 * LongPoller<Message> poller( new LongPoller.Publish<Message>()
 * 
 * @Override public void doPublish(Message result) {
 *           Window.alert(result.toString()); } }, new
 *           LongPoller.Query<Message>() {
 * @Override public void doQuery(AsyncCallback<Message> callback) {
 *           api.Inbox(sessionId, callback); } }); // start the code
 *           poller.start(); }
 * */
public class Poller<T>
		implements AsyncCallback<T> {

	public static interface Publish<T> {
		public void doPublish(T result);
	}

	public static interface Query<T> {
		public void doQuery(AsyncCallback<T> callback);
	}

	public Poller(Query<T> query, Publish<T> publish) {
		this(query, publish, Integer.MAX_VALUE);
	}

	public Poller(Query<T> query, Publish<T> publish, int maxPolls) {
		this.maxInvocations = maxPolls;
		this.publish = publish;
		this.query = query;
	}

	@Override
	public void onSuccess(T result) {
		invoker.schedule(successSchedule);
		publish.doPublish(result);
	}

	@Override
	public void onFailure(Throwable caught) {
		invoker.schedule(failiureSchedule);
	}

	public void start() {
		invocations = 0;
		stop = false;
		invoker.schedule(successSchedule);
	}

	public void run() {
		invoker.run();
	}

	public void stop() {
		stop = true;
	}

	private Query<T> query;
	private Publish<T> publish;
	private boolean stop = false;
	private int maxInvocations;
	private int invocations = 0;
	private int successSchedule = 25;
	private int failiureSchedule = 500;
	private Timer invoker = new Timer() {

		@Override
		public void run() {

			if (stop)
				return;
			else
				stop = ++invocations >= maxInvocations;

			query.doQuery(Poller.this);
		}
	};
}
